﻿#include "bb_api.h"
#include "getopt.h"
#include <cstdlib>
#include <stdio.h>

#ifdef WIN32
#include <Windows.h>
#else
#include <unistd.h>
#endif

#include <string.h>
struct pair_cfg {
    int      slot       = 0;
    int      master_flg = 0;
    int      slave_flg  = 0;
    int      set_mac    = 0;
    bool     force_ap   = 0;
    int      role       = 0;
    int      pair_succ  = 0;
    bb_mac_t mac        = { { 0 } };
};

static bb_dev_handle_t* bb_dev_open_by_flg(bb_dev_t** devs, int num, pair_cfg& cfg)
{
    cfg.force_ap = cfg.master_flg || cfg.slave_flg;

    for (int i = 0; i < num; i++) {
        bb_dev_handle_t* phd = bb_dev_open(devs[i]);
        if (!phd) {
            continue;
        }
        bb_get_status_in_t  in  = { 0 };
        bb_get_status_out_t out = { 0 };
        bb_ioctl(phd, BB_GET_STATUS, &in, &out);
        cfg.role = out.role;

        if (!cfg.force_ap) {
            return phd;
        } else if (out.role == BB_ROLE_AP) {
            if (out.sync_master && cfg.master_flg) {
                return phd;
            } else if (!out.sync_master && cfg.slave_flg) {
                return phd;
            }
        }
    }

    return NULL;
}

int main(int argc, char** argv)
{
    pair_cfg cfg;

    while (1) {
        int                  option_index   = 0;
        static struct option long_options[] = {
            {"user",    required_argument, 0, 'u'},
            { "master", no_argument,       0, 'm'},
            { "slave",  no_argument,       0, 's'},
            { "auto",   no_argument,       0, 'a'},
            { "help",   no_argument,       0, 'h'},
            { 0,        0,                 0, 0  },
        };

        int c = getopt_long(argc, argv, "u:msah", long_options, &option_index);
        if (c == -1) {
            break;
        }

        switch (c) {
        case 'u':
            cfg.slot = strtoul(optarg, NULL, 10);
            break;
        case 'm':
            cfg.master_flg = 1;
            break;
        case 's':
            cfg.slave_flg = 1;
        case 'a':
            cfg.set_mac = 1;
            break;
        case 'h':
            break;
        default:
            break;
        }
    }

    bb_host_t* phost = NULL;

    if (bb_host_connect(&phost, "127.0.0.1", 50000)) {
        printf("failed to connect host!\n");
        return -1;
    }

    bb_dev_t** devs;

    int sz = bb_dev_getlist(phost, &devs);
    if (sz <= 0) {
        printf("dev cnt = 0\n");
        return -1;
    }

    bb_dev_handle_t* pdev = bb_dev_open_by_flg(devs, sz, cfg);
    if (!pdev) {
        printf("can't open dev!!\n");
        return -1;
    }
    printf("start bb_pair\n");
    // start
    if (cfg.role == BB_ROLE_DEV) {
        cfg.slot = 0;
    }
    uint8_t slot_bmp = 1 << cfg.slot;
    int     count    = 0;

    bb_set_pair_mode_t pair_para;
    pair_para.slot_bmp = slot_bmp;
    pair_para.start    = 1;
    bb_ioctl(pdev, BB_SET_PAIR_MODE, &pair_para, NULL);
    // suppose pair in 3s
    for (int i = 0; i < 150; i++) {
#ifdef WIN32
        Sleep(20);
#else
        usleep(20 * 1000);
#endif
        bb_get_pair_out_t pair_out = { 0 };
        bb_ioctl(pdev, BB_GET_PAIR_RESULT, NULL, &pair_out);
        if (!pair_out.slot_bmp) {
            continue;
        }

        if (++count <= 5) {
            continue;
        }
        int slot_index = -1;
        for (int bit = 0; bit < 8; bit++) {
            if (pair_out.slot_bmp & (1 << bit)) {
                slot_index = bit;
                break;
            }
        }
        if (cfg.role == BB_ROLE_AP) {
            memcpy(&cfg.mac, pair_out.peer_mac + cfg.slot, sizeof(bb_mac_t));
        } else {
            memcpy(&cfg.mac, pair_out.peer_mac + slot_index, sizeof(bb_mac_t));
        }

        printf("remote mac:%02x-%02x-%02x-%02x slot_index=%d\n",
               cfg.mac.addr[0],
               cfg.mac.addr[1],
               cfg.mac.addr[2],
               cfg.mac.addr[3],
               slot_index);
        cfg.pair_succ = 1;
        break;
    }
    // stop
    pair_para.start = 0;
    bb_ioctl(pdev, BB_SET_PAIR_MODE, &pair_para, NULL);

    if (!cfg.pair_succ) {
        printf("pair failed\n");
    }

    if (cfg.set_mac) {
        printf("set remote mac\n");
        if (cfg.role == BB_ROLE_AP) {
            bb_set_candidate_t candi;
            candi.slot = cfg.slot;
            memcpy(candi.mac_tab, &cfg.mac, sizeof(bb_mac_t));
            candi.mac_num = 1;
            bb_ioctl(pdev, BB_SET_CANDIDATES, &candi, NULL);
        } else {
            bb_set_ap_mac_t ap_mac;
            memcpy(&ap_mac.mac, &cfg.mac, sizeof(bb_mac_t));
            bb_ioctl(pdev, BB_SET_AP_MAC, &ap_mac, NULL);
        }
    }
    printf("pair finish\n");

    return 0;
}